package cn.baage.campus.service.impl;

import cn.baage.campus.constant.CacheConstant;
import cn.baage.campus.mapper.PostingDetailMapper;
import cn.baage.campus.mapper.PostingImgMapper;
import cn.baage.campus.mapper.PostingMapper;
import cn.baage.campus.model.dto.LoginUser;
import cn.baage.campus.model.po.Posting;
import cn.baage.campus.model.po.PostingDetail;
import cn.baage.campus.model.po.PostingImg;
import cn.baage.campus.model.vo.PostingAddReqVO;
import cn.baage.campus.model.vo.PostingDetailResVO;
import cn.baage.campus.model.vo.PostingResVO;
import cn.baage.campus.model.vo.PostingQueryReqVO;
import cn.baage.campus.service.LikeService;
import cn.baage.campus.service.PostingService;
import cn.baage.campus.service.RedisService;
import cn.baage.campus.utils.DateUtils;
import cn.baage.campus.utils.MinioUtils;
import cn.baage.campus.utils.PageUtils;
import cn.baage.campus.utils.SecurityUtils;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description: 帖子Service实现
 * @Author: 八阿哥
 * @url: baage.cn
 * @Version: 1.0
 **/
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class PostingServiceImpl extends ServiceImpl<PostingMapper, Posting> implements PostingService {

    private final PostingDetailMapper postingDetailMapper;
    private final PostingImgMapper postingImgMapper;

    private final LikeService likeService;
    private final RedisService<Integer> redisService;

    private final MinioUtils minioUtils;


    /**
     * 查询帖子列表
     *
     * @param postingQueryReqVO 查询条件
     * @return 帖子列表
     */
    @Override
    public List<PostingResVO> listPosting(PostingQueryReqVO postingQueryReqVO) {
        List<PostingResVO> postingRes = this.baseMapper.selectPosting(postingQueryReqVO);
        postingRes.forEach(p -> {
            p.setAvatarUrl(minioUtils.getAccessUrl(p.getAvatarUrl()));
            p.setShowTime(DateUtils.formatTimeDifferenceNow(p.getCreateTime()));
        });
        return postingRes;
    }


    /**
     * 查询热点帖子
     *
     * @return 热点帖子
     */
    @Override
    public List<PostingResVO> listHotPosting() {
        return this.baseMapper.selectHotPosting();
    }


    /**
     * 获取热点帖子（缓存）
     *
     * @return 热点帖子(缓存)
     */
    @Override
    public List<PostingResVO> listHosPostingCache() {
        String hostCache = redisService.getJsonVal(CacheConstant.HOT_POSTING_KEY);
        if (StrUtil.isBlank(hostCache)) {
            return new ArrayList<>();
        }
        return JSON.parseArray(hostCache, PostingResVO.class);
    }


    /**
     * 获取帖子详情
     *
     * @return 帖子详情
     */
    @Override
    public PostingDetailResVO getPostingDetail(String postingId) {
        PostingDetailResVO postingDetailRes = this.baseMapper.selectPostingDetail(postingId);
        List<PostingImg> postingImgList = postingImgMapper.selectByPostingId(postingId);
        List<String> postingImgUrls = postingImgList.stream()
                .map(p -> minioUtils.getAccessUrl(p.getImgPath())).collect(Collectors.toList());
        postingDetailRes.setImgList(postingImgUrls);
        postingDetailRes.setAvatarUrl(minioUtils.getAccessUrl(postingDetailRes.getAvatarUrl()));
        postingDetailRes.setShowTime(DateUtils.formatTimeDifferenceNow(postingDetailRes.getCreateTime()));
        if (SecurityUtils.isLogin()) {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            boolean licked = likeService.checkLike(postingId, loginUser.getId(), 1);
            if (licked) {
                postingDetailRes.setLikeStatus(1);
            }
            String key = CacheConstant.LIKE_NUM_KEY + "1:" + postingId;
            Integer unCacheNum = redisService.get(key);
            if (unCacheNum != null) {
                postingDetailRes.setLikeNum(postingDetailRes.getLikeNum() + unCacheNum);
            }
        }
        incrReadingNum(postingId);
        return postingDetailRes;
    }


    /**
     * 新增帖子
     *
     * @param postingAddReqVO 帖子内容
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addPosting(PostingAddReqVO postingAddReqVO) {
        String postingId = IdUtil.simpleUUID();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Date now = new Date();
        // 帖子信息
        Posting posting = new Posting();
        posting.setId(postingId);
        int length = postingAddReqVO.getDetail().length();
        posting.setAbstractContent(postingAddReqVO.getDetail().substring(0, Math.min(length, 100)).replace("\n", "<br>"));
        if (length > 100) {
            posting.setAbstractContent(posting.getAbstractContent() + "...");
        }
        posting.setCategoryId(postingAddReqVO.getCategoryId());
        posting.setUserId(loginUser.getId());
        posting.setCreateTime(now);
        posting.setUpdateTime(now);
        if (postingAddReqVO.getImgList() != null && !postingAddReqVO.getImgList().isEmpty()) {
            posting.setHaveImg(Boolean.TRUE);
            posting.setImgNum(postingAddReqVO.getImgList().size());
            // 保存帖子图片
            List<PostingImg> postingImgList = new ArrayList<>();
            postingAddReqVO.getImgList().forEach(path -> {
                PostingImg postingImg = new PostingImg();
                postingImg.setPostingId(postingId);
                postingImg.setImgPath(path);
                postingImgList.add(postingImg);
            });
            postingImgMapper.insertBatch(postingImgList);
        }
        this.baseMapper.insert(posting);
        // 帖子详情
        PostingDetail postingDetail = new PostingDetail();
        String detail = postingAddReqVO.getDetail().replace("\n", "<br>");
        postingDetail.setPostingId(postingId);
        postingDetail.setDetail(detail);
        postingDetailMapper.insert(postingDetail);
    }


    /**
     * 处理点赞
     *
     * @param postingId 帖子ID
     * @param likeType 点赞类型：0 取消点赞，1 点赞
     */
    @Override
    public void likePosting(String postingId, Integer likeType) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (likeType == 0) {
            // 取消点赞
            likeService.unlike(postingId, loginUser.getId(),1);
        } else if (likeType == 1) {
            // 点赞
            likeService.like(postingId, loginUser.getId(),1);
        }
    }


    /**
     * 更新热点分数
     *
     * @param postingId 帖子ID
     * @param score 热点分数
     */
    @Override
    public void updateHotScore(String postingId, Double score) {
        this.update().set("hot_score", score).eq("id", postingId).update();
    }

    /**
     * 更新喜欢数
     *
     * @param postingId 帖子ID
     * @param num 喜欢数
     */
    @Override
    public void updateLikeNum(String postingId, Integer num) {
        if (num == 0) {
            return;
        }
        String updateNumSql;
        if (num > 0) {
            updateNumSql = "like_num = like_num + " + num;
        } else {
            updateNumSql = "like_num = like_num - " + Math.abs(num);
        }
        this.update().setSql(updateNumSql).eq("id", postingId).update();
    }



    /**
     * 更新阅读数
     *
     * @param postingId 帖子ID
     * @param num 阅读数
     */
    @Override
    public void updatePostingReadNum(String postingId, Integer num) {
        if (num == 0) {
            return;
        }
        String updateNumSql;
        if (num > 0) {
            updateNumSql = "read_num = read_num + " + num;
        } else {
            updateNumSql = "read_num = read_num - " + Math.abs(num);
        }
        this.update().setSql(updateNumSql).eq("id", postingId).update();
    }



    /**
     * 添加阅读数
     *
     * @param postingId 帖子ID
     */
    private void incrReadingNum(String postingId) {
        String key = CacheConstant.READING_NUM_KEY + postingId;
        redisService.increment(key, 1L);
    }


}
